#include "LogicEdit.h"

string LogicEdit::execute(Parser::PARSED_COMMAND parsedCommand, 
									vector<Task>& tasksVector,
									Data* _data,
									Writer* _writer) {
	string status;

	if( parsedCommand.commandType == Parser::EDIT_RENAME ) {
		status = editTaskByName(parsedCommand, tasksVector, _data, _writer);
	} else if( parsedCommand.commandType == Parser::EDIT_START_DATETIME ) {
		status = editTaskByStartDateTime(parsedCommand, tasksVector, _data, _writer);
	} else if( parsedCommand.commandType == Parser::EDIT_START_TIME ) {
		status = editTaskByStartTime(parsedCommand, tasksVector, _data, _writer);
	} else if( parsedCommand.commandType == Parser::EDIT_END_DATETIME ) {
		status = editTaskByEndDateTime(parsedCommand, tasksVector, _data, _writer);
	} else if( parsedCommand.commandType == Parser::EDIT_END_TIME ) {
		status = editTaskByEndTime(parsedCommand, tasksVector, _data, _writer);
	}

	return status;
}

string LogicEdit::editTaskByName(Parser::PARSED_COMMAND parsedCommand, 
									vector<Task>& tasksVector,
									Data* _data,
									Writer* _writer) {

	string statusMessage;
	int index;
	int taskID;
	string newTaskName;
	Data::DataFeedback dataFeedback;
	vector<Task> tasks;
	bool outOfBounds;

	// get user input
	index = parsedCommand.editTaskID;
	newTaskName = parsedCommand.editTaskName;

	outOfBounds = isOutOfBounds(index, tasksVector.size());

	// empty and out of bounds taken care of here
	if( outOfBounds ) {
		throw(INDEX_OUT_OF_BOUNDS_ERROR_MESSAGE);
	}
	
	// find task on display
	taskID = tasksVector[index-1].getTaskID();

	// if no changes made
	if( tasksVector[index-1].getTaskName() == newTaskName ) {
		throw(NO_CHANGES_ERROR_MESSAGE);
	}

	// set editted task attributes
	tasksVector[index-1].setTaskName(newTaskName);
	_task = tasksVector[index-1];

	// update internal data
	dataFeedback = _data->executeEdit(_task);

	if( dataFeedback == Data::FAILURE ) {
		//////logErrors(EDIT_ERROR_MESSAGE, _undoState);
		throw(EDIT_ERROR_MESSAGE);
	}
	
	tasksVector.clear();
	_data->getByID(tasks, taskID);
	copyTasks(tasks, tasksVector);
	tasks.clear();
	_data->getAll(tasks);
	_writer->write(tasks);

	statusMessage = EDIT_SUCCESS_MESSAGE;

	return statusMessage;
}

string LogicEdit::editTaskByStartTime(Parser::PARSED_COMMAND parsedCommand, 
									vector<Task>& tasksVector,
									Data* _data,
									Writer* _writer) {

	string statusMessage;
	int index;
	int taskID;
	time_duration newStartTime;
	ptime oldStartDateTime;
	ptime newStartDateTime;
	Data::DataFeedback dataFeedback;
	vector<Task> tasks;
	bool outOfBounds;

	// get user input
	index = parsedCommand.editTaskID;
	newStartTime = parsedCommand.editStartTime;

	outOfBounds = isOutOfBounds(index, tasksVector.size());

	if( outOfBounds ) {
		throw(INDEX_OUT_OF_BOUNDS_ERROR_MESSAGE);
	}

	// find task on display
	taskID = tasksVector[index-1].getTaskID();

	if( tasksVector[index-1].getStartDateTime().time_of_day() == newStartTime ) {
		throw(NO_CHANGES_ERROR_MESSAGE);
	}

	// set editted task attributes
	tasksVector[index-1].setStartTime(newStartTime);
	_task = tasksVector[index-1];

	// update internal data
	dataFeedback = _data->executeEdit(_task);

	if( dataFeedback == Data::FAILURE ) {
		//logErrors(EDIT_ERROR_MESSAGE, _undoState);
		throw(EDIT_ERROR_MESSAGE);
	}

	tasksVector.clear();
	_data->getByID(tasks, taskID);
	copyTasks(tasks, tasksVector);
	tasks.clear();
	_data->getAll(tasks);
	_writer->write(tasks);

	statusMessage = EDIT_SUCCESS_MESSAGE;

	return statusMessage;
}

string LogicEdit::editTaskByEndTime(Parser::PARSED_COMMAND parsedCommand, 
									vector<Task>& tasksVector,
									Data* _data,
									Writer* _writer) {

	string statusMessage;
	int index;
	int taskID;
	time_duration newEndTime;
	Data::DataFeedback dataFeedback;
	vector<Task> tasks;
	bool outOfBounds;

	// get user input
	index = parsedCommand.editTaskID;
	newEndTime = parsedCommand.editEndTime;

	outOfBounds = isOutOfBounds(index, tasksVector.size());

	if( outOfBounds ) {
		throw(INDEX_OUT_OF_BOUNDS_ERROR_MESSAGE);
	}

	// find task on display
	taskID = tasksVector[index-1].getTaskID();

	if( tasksVector[index-1].getEndDateTime().time_of_day() == newEndTime ) {
		throw(NO_CHANGES_ERROR_MESSAGE);
	}

	// set editted task attributes
	tasksVector[index-1].setEndTime(newEndTime);
	_task = tasksVector[index-1];

	// update internal data
	dataFeedback = _data->executeEdit(_task);

	if( dataFeedback == Data::FAILURE ) {
		//logErrors(EDIT_ERROR_MESSAGE, _undoState);
		throw(EDIT_ERROR_MESSAGE);
	}

	tasksVector.clear();
	_data->getByID(tasks, taskID);
	copyTasks(tasks, tasksVector);
	tasks.clear();
	_data->getAll(tasks);
	_writer->write(tasks);

	statusMessage = EDIT_SUCCESS_MESSAGE;

	return statusMessage;
}

string LogicEdit::editTaskByStartDateTime(Parser::PARSED_COMMAND parsedCommand, 
									vector<Task>& tasksVector,
									Data* _data,
									Writer* _writer) {
	
	string statusMessage;
	int index;
	int taskID;
	ptime newStartDateTime;
	Data::DataFeedback dataFeedback;
	vector<Task> tasks;
	bool outOfBounds;

	// get user input
	index = parsedCommand.editTaskID;
	newStartDateTime = parsedCommand.editStartDateTime;

	outOfBounds = isOutOfBounds(index, tasksVector.size());

	if( outOfBounds ) {
		throw(INDEX_OUT_OF_BOUNDS_ERROR_MESSAGE);
	}

	// find task on display
	taskID = tasksVector[index-1].getTaskID();

	if( tasksVector[index-1].getStartDateTime() == newStartDateTime ) {
		throw(NO_CHANGES_ERROR_MESSAGE);
	}

	// set editted task attributes
	tasksVector[index-1].setStartDateTime(newStartDateTime);
	_task = tasksVector[index-1];

	// update internal data
	dataFeedback = _data->executeEdit(_task);

	if( dataFeedback == Data::FAILURE ) {
		//logErrors(EDIT_ERROR_MESSAGE, _undoState);
		throw(EDIT_ERROR_MESSAGE);
	}

	tasksVector.clear();
	_data->getByID(tasks, taskID);
	copyTasks(tasks, tasksVector);
	tasks.clear();
	_data->getAll(tasks);
	_writer->write(tasks);

	statusMessage = EDIT_SUCCESS_MESSAGE;

	return statusMessage;
}

string LogicEdit::editTaskByEndDateTime(Parser::PARSED_COMMAND parsedCommand, 
									vector<Task>& tasksVector,
									Data* _data,
									Writer* _writer) {

	string statusMessage;
	int index;
	int taskID;
	ptime newEndDateTime;
	Data::DataFeedback dataFeedback;
	vector<Task> tasks;
	bool outOfBounds;

	// get user input
	index = parsedCommand.editTaskID;
	newEndDateTime = parsedCommand.editEndDateTime;

	outOfBounds = isOutOfBounds(index, tasksVector.size());

	if( outOfBounds ) {
		throw(INDEX_OUT_OF_BOUNDS_ERROR_MESSAGE);
	}

	// find task on display
	taskID = tasksVector[index-1].getTaskID();

	if( tasksVector[index-1].getEndDateTime() == newEndDateTime ) {
		throw(NO_CHANGES_ERROR_MESSAGE);
	}

	// set editted task attributes
	tasksVector[index-1].setEndDateTime(newEndDateTime);
	_task = tasksVector[index-1];

	// update internal data
	dataFeedback = _data->executeEdit(_task);

	if( dataFeedback == Data::FAILURE ) {
		//logErrors(EDIT_ERROR_MESSAGE, _undoState);
		throw(EDIT_ERROR_MESSAGE);
	}

	tasksVector.clear();
	_data->getByID(tasks, taskID);
	copyTasks(tasks, tasksVector);
	tasks.clear();
	_data->getAll(tasks);
	_writer->write(tasks);

	statusMessage = EDIT_SUCCESS_MESSAGE;

	return statusMessage;
}

const string LogicEdit::EDIT_SUCCESS_MESSAGE = "Edit Completed";

const string LogicEdit::EDIT_ERROR_MESSAGE = "Unable to Edit";

const string LogicEdit::NO_CHANGES_ERROR_MESSAGE = "No Changes Made";